#pragma once

#include<iostream>
#include<string>
#include<cstring>
#include<cerrno>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>

#include"err.hpp"
#include"log.hpp"

class Sock
{
    const int blockbag=32;
public:
    Sock(){}

    //创建套接字
    void Socket()
    {
        _sock=socket(AF_INET,SOCK_STREAM,0);
        if(_sock<0)
        {
            logMessage(Fatal,"create sock error,%s,errno:%d",strerror(errno),errno);
            exit(SOCKET_ERR);
        }

        logMessage(Info,"create sock success,sock:%d",_sock);
    }

    //绑定
    void Bind(const uint16_t &port)
    {
        struct sockaddr_in local;
        local.sin_family=AF_INET;
        local.sin_port=htons(port);
        local.sin_addr.s_addr=INADDR_ANY;

        if(bind(_sock,(struct sockaddr*)&local,sizeof(local))<0)
        {
            logMessage(Fatal,"bind error,%s,errno:%d",strerror(errno),errno);
            exit(BIND_ERR);
        }
    }

    //监听
    void Listen()
    {
        if(listen(_sock,blockbag)<0)
        {
            logMessage(Fatal,"listen error,%s,errno:%d",strerror(errno),errno);
            exit(LISTEN_ERR);
        }
    }

    //接收链接
    int Accept(std::string*clientIp,uint16_t*clientPort)
    {
        struct sockaddr_in client;
        memset(&client,0,sizeof(client));
        socklen_t len=sizeof(client);
        int sock=accept(_sock,(struct sockaddr*)&client,&len);
        if(sock<0)
            logMessage(Warning,"accept client error,%s,errno:%d",strerror(errno),errno);
        else
        {
            *clientIp=inet_ntoa(client.sin_addr);
            *clientPort=ntohs(client.sin_port);
        }

        return sock;
    }
    //连接服务器
    int Connect(const std::string& serverIp,const uint16_t& serverPort)
    {
        struct sockaddr_in server;
        memset(&server,0,sizeof(server));
        server.sin_family=AF_INET;
        server.sin_addr.s_addr=inet_addr(serverIp.c_str());
        server.sin_port=htons(serverPort);

        return connect(_sock,(struct sockaddr*)&server,sizeof(server));
    }

    int Fd()
    {
        return _sock;
    }

    void Close()
    {
        close(_sock);
    }
private:
    int _sock;
};